package com.blog.Utils;

import lombok.extern.slf4j.Slf4j;
import okhttp3.*;
import org.springframework.stereotype.Component;

import java.net.URLEncoder;
import java.util.Map;
import java.util.Objects;
import java.util.concurrent.TimeUnit;

/**
 * @author 任浩
 * @version 1.0
 */

@Slf4j
public class OkHttpInstance {
    private OkHttpClient client = new OkHttpClient().newBuilder()
            .connectTimeout(10, TimeUnit.SECONDS) // 设置连接超时为10秒
            .writeTimeout(20, TimeUnit.SECONDS)     // 设置写入超时为20秒
            .readTimeout(60, TimeUnit.SECONDS)      // 设置读取超时为60秒
            .build();


    /**
     * 无参数，无请求头的get请求方式。
     * @param url
     * @return
     */
    public String get(String url){
         Request request = new Request.Builder()
                .url(url)
                .get()//默认就是GET请求，可以不写
                .build();
         return getCall(request,url);
    }

    /**
     * 这是有参数，无请求头的get请求方式。
     * @param params
     * @param url
     * @return
     */
    public String get(Map<String, Object> params,String url){
        /**
         * 把参数追加到url地址后面
         */
        if(params == null){
            throw new RuntimeException("传入的params参数不能为null");
        }

        StringBuilder sb = new StringBuilder(url);
        //判断是否有了地址中，是否有了?参数，如果没有，就添加一个。有的话，加上一个&参数
        if(sb.toString().contains("?")){
            sb.append("&");
        }else{
            sb.append("?");
        }
        params.forEach((key,data) ->{
            try {
                sb.append(URLEncoder.encode(key, "utf-8")).append("=").append(URLEncoder.encode((String) data, "utf-8")).append("&");
            }
            catch (Exception e){
                e.printStackTrace();
            }
        });
        //去除掉最后一个&
        sb.deleteCharAt(sb.length() - 1);
        log.info("请求的地址为: {}",sb.toString());
        Request request = new  Request.Builder()
                .url(sb.toString())
                .get()//默认就是GET请求，可以不写
                .build();

        return getCall(request,url);
    }


    /**
     * 这是有参数，有请求头的get请求方式。
     * @param params
     * @param headers
     * @param url
     */
    public String get(Map<String, Object> params, Map<String, String> headers, String url){
        /**
         * 把参数追加到url地址后面
         */
        if(params == null){
            throw new RuntimeException("传入的params参数不能为null");
        }

        StringBuilder sb = new StringBuilder(url);
        //判断是否有了地址中，是否有了?参数，如果没有，就添加一个。有的话，加上一个&参数
        if(sb.toString().contains("?")){
            sb.append("&");
        }else{
            sb.append("?");
        }
        params.forEach((key,data) ->{
            try {
                sb.append(URLEncoder.encode(key, "utf-8")).append("=").append(URLEncoder.encode((String) data, "utf-8")).append("&");
            }
            catch (Exception e){
                e.printStackTrace();
            }
        });
        //去除掉最后一个&
        sb.deleteCharAt(sb.length() - 1);
        log.info("请求的地址为: {}",sb.toString());

        Request.Builder requestbuilder = new Request.Builder()
                .get();//默认就是GET请求，可以不写
        requestbuilder.url(sb.toString());

        //增加请求头
        for (Map.Entry<String, String> stringObjectEntry : headers.entrySet()) {
            requestbuilder.addHeader(stringObjectEntry.getKey(),stringObjectEntry.getValue());
        }

        return getCall(requestbuilder.build(),url);

    }

    /**
     * 发送json格式的请求体的post格式的数据
     * @param url
     * @param json
     * @param headers
     * @return
     */
    public String post(String url,String json,Map<String, String> headers){
        MediaType mediaType = MediaType.parse("application/json; charset=utf-8");
        Request.Builder request = new Request.Builder()
                .url(url)
                .post(RequestBody.create(mediaType, json));
        //添加请求头信息
        for (Map.Entry<String, String> stringObjectEntry : headers.entrySet()) {
            request.addHeader(stringObjectEntry.getKey(), stringObjectEntry.getValue());
        }

        return getCall(request.build(),url);
    }

    /**
     * 发送/x-www-form-urlencoded 格式的请求体的post格式的数据
     * @param url
     * @param json
     * @param headers
     * @return
     */
    public String postXXXForm(String url,String json,Map<String, String> headers){
        MediaType mediaType = MediaType.parse("application/x-www-form-urlencoded");
        Request.Builder request = new Request.Builder()
                .url(url)
                .post(RequestBody.create(mediaType, json));
        //添加请求头信息
        for (Map.Entry<String, String> stringObjectEntry : headers.entrySet()) {
            request.addHeader(stringObjectEntry.getKey(), stringObjectEntry.getValue());
        }

        return getCall(request.build(),url);
    }


    /**
     * 参数为map集合的请求方式。
     * @param url
     * @param paramMap
     */
    public String post(String url, Map<String, Object> paramMap,Map<String,String> heardMap) {
        FormBody.Builder formBody = new FormBody.Builder();
        if (Objects.nonNull(paramMap)) {
            paramMap.forEach((x, y) -> formBody.add(x, (String) y));
        }
        RequestBody requestBody = formBody.build();
        Request.Builder requestbuilder = new Request.Builder()
                .url(url)
                .post(requestBody);
        //增加请求头
        for (Map.Entry<String, String> stringObjectEntry : heardMap.entrySet()) {
            requestbuilder.addHeader(stringObjectEntry.getKey(), stringObjectEntry.getValue());
        }

        Request request = requestbuilder.build();
        return getCall(request,url);
    }


    public String getCall(Request request,String url){
        try {
            Response response = client.newCall(request).execute();
            String data = response.body().string();
            log.info("调用{}接口,得到的返回数据为: {}",url,data);
            return data;
        }
        catch (Exception e){
            log.error("[调用{}接口失败,报错信息为: {}]",url,e.getMessage());
            //todo  这里异常类，应该专门建一个第三方调用异常的类。
            throw new RuntimeException("调用接口失败：" + e.getMessage());
        }
    }
}
